package client;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;

public abstract class AbstractClientFactory implements ClientFactory{
    protected AbstractClientFactory() {
    }

    private static final ConcurrentHashMap<String, FutureTask<List<Client>>> clients = new ConcurrentHashMap<>();

    @Override
    public Client get(String targetIp, int port, int timeout) throws Exception {

        return this.get(targetIp, port, 1, timeout);
    }

    @Override
    public Client get(String targetIp, int port, int clientNums, int timeout) throws Exception {
        String key = targetIp + ":" + port;
        if (clients.contains(key)) {
            if (clientNums == 1) {
                clients.get(key).get().get(0);
            } else {
                Random random = new Random();
                clients.get(key).get().get(random.nextInt(clientNums));
            }
        } else {
            FutureTask<List<Client>> task = new FutureTask<>((Callable<List<Client>>) () -> {
                ArrayList<Client> list = new ArrayList<>();
                for (int i = 0; i < clientNums; i++) {
                    list.add(createClient(targetIp, port, timeout));
                }
                return list;
            });
            FutureTask<List<Client>> listFutureTask = clients.putIfAbsent(key, task);
            if (listFutureTask == null) {
                task.run();
            } else {
                task = listFutureTask;
            }
            if (clientNums == 1) {
                return task.get().get(0);
            } else {
                Random random = new Random();
                task.get().get(random.nextInt(clientNums));
            }


        }
        return null;
    }

    @Override
    public void removeClient(String targetIp, int port) {

    }

    protected abstract Client createClient(String targetIp, int port, int connectionTimeout)throws Exception;
//    protected abstract Client createClient(String targetIP, int targetPort, int connectTimeout, String key) throws Exception;
}
